﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Xml.Linq;
using System.Xml.XPath;
using System.IO;

namespace OffLineFilter
{
    public class SolutionTreeResolver
    {
        public enum OperationType
        {
            dcsLessThanThresold,
            dcsGreaterThanThresoldOrEqu
        }

        private delegate bool Operation(double param1, double param2);
        private Operation[] operations = new Operation[] 
        {
            (param1, param2) => param1 < param2,
            (param1, param2) => param1 >= param2
        };

        private String fileName;
        public String FileName
        {
            get { return fileName; }
        }

        private XElement document;

        private string solution;
        public string Solution
        {
            get { return solution; }
        }

        private string leafId;
        public string LeafId
        {
            get { return leafId; }
        }

        private Dictionary<int, double> data;
        public Dictionary<int, double> Data
        {
            get { return data; }
        }

        private Dictionary<int, String> decisions;

        public SolutionTreeResolver(String fileName, Dictionary<int, double> data)
        {
            if (String.IsNullOrWhiteSpace(fileName))
                throw new ArgumentException();
            this.fileName = fileName;
            this.data = data;
        }

        public bool Parse()
        {
            try
            {
                document = XElement.Parse(File.ReadAllText(fileName, Encoding.Default));
                decisions = document
                    .XPathSelectElements("/DecisionValues/Value")
                    .ToDictionary(value => (int)value.Attribute("id"), 
                        value => (string)value.Element("DisplayName"));

                var node = document.XPathSelectElement("/Tree/Node");
                solution = Solve(node);
            }
            catch
            {
                return false;
            }
            return true;
        }

        public String Solve(XElement node)
        {
            XElement subnodes = node.Element("SubNodes");
            if (subnodes != null)
            {
                var nodes = subnodes.Elements("Node");
                foreach (var n in nodes)
                {
                    solution = Solve(n);
                    if (!String.IsNullOrWhiteSpace(solution))
                    {
                        if (String.IsNullOrWhiteSpace(leafId))
                            leafId = (string)n.Attribute("id");
                        return solution;
                    }
                }
            }

            int decision = (int)node.Element("Decision");
            XElement condition = node.Element("Condition");
            int dataIndex = (int)condition.Element("InputColumnIndex");
            double threshold = (double)condition.Element("Threshold");

            OperationType operation;
            Enum.TryParse(condition.Element("ConditionSign").ToString(), out operation);

            if (operations[(int)operation](data[dataIndex], threshold))
                return decisions[decision];

            return null;
        }
    }
}
